//实现vue computed
class Computed {
  constructor() {
    /**
     * {
     *   key: total,
     *   value: 3 - 运算后的结果
     *   get: totalFn,
     *   dep: [a, b]
     * }
     */
    this.computedData = [];
  }

  //增加
  addComputed(vm, computed, key) {
    const
      descriptor = Object.getOwnPropertyDescriptor(computed, key),
      descriptorFn = descriptor.value.get ? descriptor.value.get : descriptor.value,
      value = descriptorFn.call(vm),
      get = descriptorFn.bind(vm),
      dep = this._collectDep(descriptorFn);

    //将指定数据对象push到实例的数组computedData
    this._addComputedProp({
      key,
      value,
      get,
      dep
    });

    // console.log(this.computedData);
    /**
     * [
     *   {
     *      key: "total",
     *      value: 3,
     *      get: ƒ (),
     *      dep: (2) ["a", "b"]
     *   }
     * ]
     */

    //找到当前项
    const dataItem = this.computedData.find(item => item.key === key);
    Object.defineProperty(vm, key, {
      get() {
        return dataItem.value;
      },
      set() {
        //拿到执行后的结果
        dataItem.value = dataItem.get();
      }
    });

  }

  //更新
  //每次依赖变更的时候都会重新执行函数
  update(key, watch) {
    this.computedData.map(item => {
      const dep = item.dep;
      const _key = dep.find(el => el == key);

      if (_key) {
        const oldValue = item.value;
        item.value = item.get();
        watch(item.key, item.value, oldValue);
      }
    })
  }

  //专门的函数处理push
  _addComputedProp(computedProp) {
    this.computedData.push(computedProp);
  }

  //收集函数名称
  _collectDep(fn) {
    const matched = fn.toString().match(/this\.(.+?)/g);
    return matched.map(item => item.split('.')[1]);
  }
}

export default Computed;